package com.example.exception;

import com.example.model.ErrorResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;

import java.lang.reflect.Field;
import java.sql.SQLException;

import static org.junit.jupiter.api.Assertions.*;

class GlobalExceptionHandlerTest {

    private GlobalExceptionHandler handler;
    private SqlExceptionHandler sqlExceptionHandler;

    @BeforeEach
    void setUp() throws Exception {
        sqlExceptionHandler = new SqlExceptionHandler();
        handler = new GlobalExceptionHandler();
        
        // 使用反射设置私有字段
        Field field = GlobalExceptionHandler.class.getDeclaredField("sqlExceptionHandler");
        field.setAccessible(true);
        field.set(handler, sqlExceptionHandler);
    }

    @Test
    void testHandleConfigurationError() {
        DatabaseConfigurationException ex = new DatabaseConfigurationException("配置错误");
        ResponseEntity<ErrorResponse> response = handler.handleConfigurationError(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
        assertNotNull(response.getBody().getTimestamp());
    }

    @Test
    void testHandleConnectionError() {
        DatabaseConnectionException ex = new DatabaseConnectionException("连接错误");
        ResponseEntity<ErrorResponse> response = handler.handleConnectionError(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
        assertNotNull(response.getBody().getTimestamp());
    }

    @Test
    void testHandleSqlExceptionWithAuthError() {
        SQLException ex = new SQLException("Access denied for user", "28000", 1045);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithConnectionError() {
        SQLException ex = new SQLException("Communications link failure", "08001", 0);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithAccessDenied() {
        SQLException ex = new SQLException("Access denied for database", "42000", 1044);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithUnknownDatabase() {
        SQLException ex = new SQLException("Unknown database 'test'", "42000", 1049);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithConnectionRefused() {
        SQLException ex = new SQLException("Connection refused", "08S01", 0);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithTimeout() {
        SQLException ex = new SQLException("Connection timed out", "08S01", 0);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithBadHandshake() {
        SQLException ex = new SQLException("Bad handshake", "08S01", 0);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithGenericError() {
        SQLException ex = new SQLException("Some unknown error", "HY000", 0);
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleSqlExceptionWithNullSqlState() {
        SQLException ex = new SQLException("Error without SQLState");
        ResponseEntity<ErrorResponse> response = handler.handleSql(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleOtherException() {
        RuntimeException ex = new RuntimeException("Unexpected error");
        ResponseEntity<ErrorResponse> response = handler.handleOther(ex);

        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("INTERNAL_ERROR", response.getBody().getCode());
        assertEquals("系统内部错误", response.getBody().getMessage());
    }

    @Test
    void testHandleValidationException() {
        // 创建一个简单的验证异常用于测试
        MethodArgumentNotValidException ex = new MethodArgumentNotValidException(
                null, 
                new org.springframework.validation.BeanPropertyBindingResult(new Object(), "object")
        );
        ResponseEntity<ErrorResponse> response = handler.handleValidation(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("VALIDATION_ERROR", response.getBody().getCode());
        assertEquals("请求参数格式不正确", response.getBody().getMessage());
    }
} 